package com.zoffy.oj_backend.judge.codesandbox.impl.ExampleCodeSandbox;

import cn.hutool.core.io.FileUtil;
import com.zoffy.oj_backend.common.ErrorCode;
import com.zoffy.oj_backend.exception.BusinessException;
import com.zoffy.oj_backend.judge.codesandbox.CodeSandbox;
import com.zoffy.oj_backend.judge.codesandbox.impl.ExampleCodeSandbox.codeExcuter.CodeExecutor;
import com.zoffy.oj_backend.judge.codesandbox.impl.ExampleCodeSandbox.codeExcuter.JavaCodeExecutor;
import com.zoffy.oj_backend.judge.codesandbox.impl.ExampleCodeSandbox.codeExcuter.PythonCodeExecutor;
import com.zoffy.oj_backend.judge.codesandbox.model.ExecuteCodeRequest;
import com.zoffy.oj_backend.judge.codesandbox.model.ExecuteCodeResponse;
import com.zoffy.oj_backend.judge.codesandbox.model.ExecuteMessage;
import com.zoffy.oj_backend.judge.codesandbox.model.JudgeInfo;
import com.zoffy.oj_backend.model.enums.JudgeInfoMessageEnum;
import com.zoffy.oj_backend.model.enums.QuestionSubmitStatusEnum;
import io.micrometer.common.util.StringUtils;
import org.springframework.stereotype.Service;

import java.io.File;

import java.util.ArrayList;
import java.util.List;

@Service
public class ExampleCodeSandbox implements CodeSandbox {

    private CodeExecutor executor;




    @Override
    public ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {
        List<String> inputList = executeCodeRequest.getInputList();
        String code = executeCodeRequest.getCode();
        String language = executeCodeRequest.getLanguage();
        //根据语言选择对应的编程语言执行器
        setLang(language);

        //运行
        try {
            //保存代码
            File codeFile = executor.saveCode2File(code);
            //编译代码
            ExecuteMessage compileMessage = executor.compileCode(codeFile);
            //编译失败
            if(compileMessage.getExitCode()!=0){
                ExecuteCodeResponse response=new ExecuteCodeResponse();
                response.setStatus(QuestionSubmitStatusEnum.EXIT_UNEXPECT.getValue());
                response.setMessage(JudgeInfoMessageEnum.COMPILE_ERROR.getText());
                response.setExtra(compileMessage.getErrorMessage());
                return response;
            }
            //获取代码结果
            List<ExecuteMessage> executeMessageList = executor.runCodeFile(codeFile, inputList);
            ExecuteCodeResponse outputResponse = getOutputResponse(executeMessageList);
            deleteFile(codeFile);
            return outputResponse;
        } catch (Exception e) {
            return getErrorResponse(e);
        }
    }
    private void setLang(String language) {
        switch (language.toLowerCase()) {
            case "java" -> executor = new JavaCodeExecutor();
            case "python" -> executor = new PythonCodeExecutor();
            default -> throw new BusinessException(ErrorCode.PARAMS_ERROR, "暂不支持该语言: " + language);
        }
    }


    public ExecuteCodeResponse getOutputResponse(List<ExecuteMessage> executeMessageList) {
        ExecuteCodeResponse executeCodeResponse = new ExecuteCodeResponse();
        List<String> outputList = new ArrayList<>();
        long maxTime = 0;
        for (ExecuteMessage executeMessage : executeMessageList) {
            String errorMessage = executeMessage.getErrorMessage();
            if (StringUtils.isNotBlank(errorMessage)) {
                executeCodeResponse.setMessage(JudgeInfoMessageEnum.RUNTIME_ERROR.getText());
                executeCodeResponse.setExtra(errorMessage);
                executeCodeResponse.setStatus(QuestionSubmitStatusEnum.EXIT_UNEXPECT.getValue());
                break;
            }
            outputList.add(executeMessage.getMessage());
            long time = executeMessage.getTime();
            maxTime = Math.max(time, maxTime);
        }
        if (outputList.size() == executeMessageList.size()) {
            executeCodeResponse.setStatus(QuestionSubmitStatusEnum.EXIT_NORMAL.getValue());
        }
        executeCodeResponse.setOutputList(outputList);
        JudgeInfo judgeInfo = new JudgeInfo();
        judgeInfo.setTime(maxTime);
        executeCodeResponse.setJudgeInfo(judgeInfo);
        return executeCodeResponse;
    }

    public void deleteFile(File file) {
        File parentFile = file.getParentFile();
        if (parentFile != null) {
            FileUtil.del(parentFile);
        }
    }

    private ExecuteCodeResponse getErrorResponse(Exception e) {
        ExecuteCodeResponse executeCodeResponse = new ExecuteCodeResponse();
        executeCodeResponse.setOutputList(new ArrayList<>());
        executeCodeResponse.setExtra(e.getMessage());
        executeCodeResponse.setStatus(QuestionSubmitStatusEnum.SYSTEM_EXCEPTION.getValue());
        executeCodeResponse.setJudgeInfo(new JudgeInfo());
        return executeCodeResponse;
    }
}
